
//class DiscoveryResult{
//    InetAddress ofFriend;
//}
//
//DiscoveryResult findFriend(JabberAddress ofFriend);


/**
* Can be me,
* or a friend of mine,
* or a friend of my friend's.
*/
class Peer{
              PublicKey                 publicKey;
              Name                      name;

              Set<SharedFileIdentifier> sharedFileIdentifiers;

    transient IoSession                 ioSession;

    class Name{
        String value;
    }

    /**
    * Connection to a peer we don't know if we should trust.
    */
    onConnect(IoSession ioSession){
        //TODO: verify if we can trust the peer.
    }

    /**
    * Session established to trusted peer.
    */
    onSession(IoSession ioSession){
        this.ioSession = ioSession;
    }

    /**
    * Sends a message object to the peer.
    */
    void send(Message message){
        ioSession.send(message);
    }
}



/**
* Me, as I see myself.
*/
class Me{
              PrivateKey                privateKey;
              PublicKey                 publicKey;
              Peer.Name                 name;

              Set<Peer>                 trustedPeers;
              Set<SharedFileIdentifier> sharedFileIdentifiers;

    transient MessageFactory            messageFactory;
    transient Set<Peer>                 connectedPeers;


    /**
    * Asks each peer who has the file to send it to me.
    */
    Future download(FileIdentifier fileIdentifierToDownload){
        for (Peer connectedPeer : connectedPeers){
            for (SharedFileIdentifiers sharedFileIdentifier: sharedFileIdentifiers){
                if (fileIdenfierToDownload.equals(sharedFileIdentifier){
                    trustedPeer.send(messageFactory.createStartUploadingToMe(sharedFileIdentifier));
                }
            }
        }
    }

    /**
    * Callback for when a peer asks us for a list of our shared files.
    */
    void receivedListSharedFiles(Peer fromPeer){
        fromPeer.send(messageFactory.createTheseAreMySharedFileIdentifiers(this.sharedFileIdentifiers));
    }

    /**
    * Tries to get a stream connected to the peer in some way,
    * for example by:
    * <ul>
    *   <li>connecting directly, or</li>
    *   <li>asking them to connect to me, or</li>
    *   <li>asking someone else to tell the peer to connect to me.</li>
    * </ul>
    */
    connectTo(Peer peer){
        // TODO
    }

}






class FileIdentifier{
    InfoHash infoHash;
    String   fileName;
}

class SharedFileIdentifier{
    /**
    * 0 means local to owner of this <code>SharedFileIdentitier</code>,
    * 1 means friend of the owner of this <code>SharedFileIdentitier</code>,
    * 2 means friend of their friend,
    * and so on.... 
    * If this <code>SharedFileIdentitier</code> belongs to {@link Me}, then 0 means local, 1 means friend and 2 means friend of my friend...
    * If this <code>SharedFileIdentifier</code> belongs to a {@link Peer}, then 0 means local to them (i.e. to my friend), etc...
    */
    int            distance;
    FileIdentifier fileIdentifier;
}



